﻿package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;	
	import flash.events.Event;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.text.TextField;
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.lights.PointLight3D;
	import org.papervision3d.materials.BitmapMaterial;
	import org.papervision3d.objects.primitives.Plane;
	import org.papervision3d.render.BasicRenderEngine;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.view.Viewport3D;
	import org.flashdevelop.utils.FlashViewer;
	
	/*
	 * coded by moka 2009 / 06/ 19 
	 * name : moka's PerlinNoise3D
	 */
	
	public class Main extends Sprite 
	{		
		private var bmpPerlin:BitmapData;
		private var bmpBuffer:BitmapData;
		private var detailW:uint;
		private var detailH:uint;
		private var plane:Plane;
		private var scene:Scene3D;
		private var camera:Camera3D;
		private var viewport:Viewport3D;
		private var render:BasicRenderEngine;
		
		// 平面貼圖的紋理
		[Embed(source = 'shield.gif')]
		private var EmbeddedImage:Class;
		private var image:Bitmap;

		public function Main():void 
		{
			image = new EmbeddedImage();
			
			stage.scaleMode = "noScale"; // 設定場景不變形
			
			// 平面的水平垂直頂點數
			detailW = 10;
			detailH = 10;
			
			// 建立灰階 PerlinNoise
			bmpPerlin = new BitmapData(detailW, detailH, false);
			bmpPerlin.perlinNoise(5, 5, 5, 0, false, true);
			bmpPerlin.applyFilter(bmpPerlin, bmpPerlin.rect, new Point, new ColorMatrixFilter(
			[0.3, 0.59, 0.11, 0, 0,
             0.3, 0.59, 0.11, 0, 0,
             0.3, 0.59, 0.11, 0, 0,
             0, 0, 0, 1, 0]));
			 
			// BitmapData Scroll Loop 時用到的暫存圖(ENTER_FRAME 事件會用到)
			bmpBuffer = new BitmapData(1, detailH, false);
			
			// Scene3D 用來組織場景母子關係樹狀架構
 			scene = new Scene3D();

			// Camera3D 為 3D 場景可視範圍設定
			camera = new Camera3D();
			
			// Viewport3D 用在呈現於 flash 場景(其類別繼承Sprite)
			viewport = addChild(new Viewport3D(640, 480)) as Viewport3D;

			// 用以渲染 3D 場景之類別
			render = new BasicRenderEngine();

			// 建立一顆 Bitmap 材質的 3D 平面
			var bmpMat:BitmapMaterial = new BitmapMaterial(image.bitmapData, true);
			bmpMat.oneSide = false;			
			plane = new Plane(bmpMat , 1000, 1000, detailW - 1, detailW - 1);
			plane.rotationX = 60;		
			scene.addChild(plane);
			
			// 註冊 ENTER_FRAME 事件
			addEventListener(Event.ENTER_FRAME, onProcess);			
			
			// Moka's work 2009
			(addChild(new TextField()) as TextField).htmlText = "<font color='#FFFFFF'>Moka's work 2009</font>"; 
		}		
		
		private function onProcess(e:Event):void {
			
			// BitmapData Scroll Loop
			bmpBuffer.copyPixels(bmpPerlin, new Rectangle(0, 0, 1, detailH), new Point);
			bmpPerlin.scroll(-1, 0);
			bmpPerlin.draw(bmpBuffer, new Matrix(1, 0, 0, 1, detailH - 1 , 0));			
			
			// 以各個 Pixel 灰階值當作平面中各個頂點的高度
			var vcnt:uint = plane.geometry.vertices.length;
			for (var i:uint = 0; i < vcnt; i++)
			{
				var x:Number = i % detailW;
				var y:Number = Math.floor(i / detailW);
				plane.geometry.vertices[i].z = (bmpPerlin.getPixel(x, y) >> 16);
			}
			
			// 渲染 3D 場景
			render.renderScene(scene, camera, viewport);
			
			// 旋轉平面 Y 軸
			plane.rotationY = mouseX;
		}
	}	
}